﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using Dapper;
using DapperExtensions;
using MaximServices.Data;
using MaximServices.Model;
using Microsoft.Extensions.Options;
using MySql.Data.MySqlClient;

namespace MaximServices.Repository
{
    public class MockCacheRepository
    {
        private readonly DataBaseRepository _dbrsp;

        public MockCacheRepository(DataBaseRepository dbrsp)
        {
            _dbrsp = dbrsp;
        }

        public void Dispose()
        {
            _dbrsp.Database.Dispose();
        }

        public MockCache FindCache(string cacheKey)
        {
            var predicate = Predicates.Field<MockCache>(f => f.CacheKey, Operator.Eq, cacheKey);

            return _dbrsp.Database.GetList<MockCache>(predicate, null, null, false).FirstOrDefault();
        }

        public void DeleteCache(string cacheKey)
        {
            var predicate = Predicates.Field<MockCache>(f => f.CacheKey, Operator.Eq, cacheKey);

            _dbrsp.Database.Delete<MockCache>(predicate, null);
        }

        public void AddCache(MockCache mockCache)
        {
            _dbrsp.Database.Insert(mockCache, null);
        }

        /// <summary>
        /// 通过缓存进行锁
        /// </summary>
        /// <param name="mockCache"></param>
        /// <param name="timeout"></param>
        /// <param name="continueIfExists"></param>
        /// <returns></returns>
        public T LockByCache<T>(Func<T> action, MockCache mockCache, int timeout, bool continueIfExists)
        {
            if (TimeoutLockCheck(mockCache.CacheKey, timeout, continueIfExists))
            {
                return default(T);
            }

            try
            {
                //添加缓存依赖
                AddCache(mockCache);

                //执行缓存
                return action();
            }
            finally
            {
                DeleteCache(mockCache.CacheKey);
            }
        }

        /// <summary>
        /// 锁定超时检测
        /// </summary>
        /// <param name="cachekey"></param>
        /// <param name="timeout"></param>
        /// <param name="continueIfExists"></param>
        /// <returns></returns>
        private bool TimeoutLockCheck(string cachekey, int timeout, bool continueIfExists)
        {
            var dateTimeStart = DateTime.Now;
            var exists = false;

            do
            {
                var dbCache = FindCache(cachekey);

                if (dbCache == null)
                {
                    break;
                }
                else
                {
                    exists = true;
                }

                //超时
                if (DateTime.Now.Subtract(dateTimeStart).TotalMilliseconds > timeout)
                {
                    break;
                }

                System.Threading.Thread.Sleep(500);

            } while (true);

            if (exists == true && continueIfExists == false)
            {
                return true;
            }

            return false;
        }
    }
}
